﻿using System;
using System.Web.Mvc;

using Whoever.Framework.Base;
using Whoever.Framework.Struct;
using Whoever.Framework.Utils;
using Whoever.Framework.CustomException;
using Whoever.Patterns.Business;

using Whoever.Patterns.MVC.Filters;
using Whoever.Patterns.MVC.Models;

namespace Whoever.Patterns.MVC.Base
{
    public abstract class BaseController<TEntity, TFilter, TManager> : AbstractController
        where TEntity : BusinessEntity, new()
        where TFilter : Whoever.Framework.Base.Filter, new()
        where TManager : Manager<TEntity>, new()
    {
        Manager<TEntity> manager;

        public BaseController()
        {
            manager = new TManager();
        }

        protected abstract ViewModel<TEntity> GetConstructor();

        public ActionResult Main(Pager pager)
        {
            var resolvedPager = new Pager
            {
                totalResults = pager.totalResults != 0 ? pager.totalResults : 20,
                maxResults = pager.maxResults != 0 ? pager.maxResults : 20,
                page = pager.page != 0 ? pager.page : 1,
                sort = !string.IsNullOrEmpty(pager.sort) ? pager.sort : "Id",
                sortDir = !string.IsNullOrEmpty(pager.sortDir) ? pager.sortDir : "ASC"
            };

            var model = GetConstructor();
            manager.FillSelectablesRelations(model);
            model.List = manager.GetAll(ref resolvedPager);

            return View(model);
        }

        public virtual ActionResult Filter(TFilter filter, Pager pager)
        {
            var resolvedPager = new Pager
            {
                totalResults = pager.totalResults != 0 ? pager.totalResults : 20,
                maxResults = pager.maxResults != 0 ? pager.maxResults : 20,
                page = pager.page != 0 ? pager.page : 1,
                sort = !string.IsNullOrEmpty(pager.sort) ? pager.sort : "Id",
                sortDir = !string.IsNullOrEmpty(pager.sortDir) ? pager.sortDir : "ASC"
            };

            return Json(manager.GetFiltered(filter, ref resolvedPager));
        }

        [AJAXExceptionHandler]
        public virtual ActionResult Create(TEntity entity)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    manager.Insert(entity);

                    return Json(new AJAXResponse { Message = Localized.Message("Create", Framework.Enum.MessageType.Success), Success = true, MustRedirect = false });
                }
                throw new BusinessException(Localized.Message("Model", Framework.Enum.MessageType.Error));
            }
            catch (BusinessException ex)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new Exception(Localized.Message("Exception", Framework.Enum.MessageType.Error));
            }
        }

        [AJAXExceptionHandler]
        public virtual ActionResult Update(TEntity entity)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    manager.Update(entity);

                    return Json(new AJAXResponse { Message = Localized.Message("Update", Framework.Enum.MessageType.Success),  Success = true, MustRedirect = false });
                }
                throw new BusinessException(Localized.Message("Model", Framework.Enum.MessageType.Error));
            }
            catch (BusinessException ex)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new Exception(Localized.Message("Exception", Framework.Enum.MessageType.Error));
            }
        }

        [AJAXExceptionHandler]
        public virtual ActionResult Delete(TEntity entity)
        {
            try
            {
                manager.Delete(entity);

                return Json(new AJAXResponse { Success = true, MustRedirect = true, RedirectURL = Url.Action("Main#Info", "Contact") });
            }
            catch (Exception ex)
            {
                throw new Exception(Localized.Message("Exception", Framework.Enum.MessageType.Error));
            }
        }
    }
}
